/**
* @file kernel.cpp
*
* Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All Rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

#include "acl/acl_rt.h"
#include "runtime/kernel.h"
#include "log_inner.h"
#include "error_codes_inner.h"
#include "toolchain/profiling_manager.h"
#include "toolchain/resource_statistics.h"

aclrtBinary *aclrtCreateBinary(uint32_t magic, uint32_t version, const void *data, size_t dataLen)
{
  ACL_ADD_APPLY_TOTAL_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_ALLOCATOR_BINARY_DESC);
  ACL_LOG_INFO("start to execute aclrtCreateBinary");
  ACL_REQUIRES_NOT_NULL_RET_NULL_INPUT_REPORT(data);

  aclrtBinary *const binaryDesc = new(std::nothrow) aclrtBinary();
  ACL_CHECK_WITH_MESSAGE_AND_RETURN(binaryDesc != nullptr, nullptr, "Allocate memory for binaryDesc failed.");

  binaryDesc->magic = magic;
  binaryDesc->version = version;
  binaryDesc->data = data;
  binaryDesc->length = static_cast<uint64_t>(dataLen);

  ACL_ADD_APPLY_SUCCESS_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_ALLOCATOR_BINARY_DESC);
  return binaryDesc;
}

aclError aclrtDestroyBinary(aclrtBinary *binary)
{
  ACL_ADD_RELEASE_TOTAL_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_ALLOCATOR_BINARY_DESC);
  ACL_LOG_INFO("start to execute aclrtDestroyBinary");
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binary);

  ACL_DELETE_AND_SET_NULL(binary);

  ACL_ADD_RELEASE_SUCCESS_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_ALLOCATOR_BINARY_DESC);
  return ACL_SUCCESS;
}

aclError aclrtBinaryLoad(const aclrtBinary *binary, aclrtBinHandle *binHandle)
{
  ACL_ADD_APPLY_TOTAL_COUNT(acl::ACL_STATISTICS_LOAD_UNLOAD_BINARY);
  ACL_LOG_INFO("start to execute aclrtBinaryLoad");
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binary);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binHandle);

  const rtError_t rtErr = rtBinaryLoad(binary, binHandle);
  if (rtErr != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtBinaryLoad failed, runtime result = %d.", rtErr);
    return ACL_GET_ERRCODE_RTS(rtErr);
  }

  ACL_ADD_APPLY_SUCCESS_COUNT(acl::ACL_STATISTICS_LOAD_UNLOAD_BINARY);
  return ACL_SUCCESS;
}

aclError aclrtBinaryUnLoad(aclrtBinHandle binHandle)
{
  ACL_ADD_RELEASE_TOTAL_COUNT(acl::ACL_STATISTICS_LOAD_UNLOAD_BINARY);
  ACL_LOG_INFO("start to execute aclrtBinaryUnLoad");
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binHandle);

  const rtError_t rtErr = rtBinaryUnLoad(binHandle);
  if (rtErr != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtBinaryUnLoad failed, runtime result = %d.", rtErr);
    return ACL_GET_ERRCODE_RTS(rtErr);
  }

  ACL_ADD_RELEASE_SUCCESS_COUNT(acl::ACL_STATISTICS_LOAD_UNLOAD_BINARY);
  return ACL_SUCCESS;
}

aclError aclrtBinaryGetFunction(const aclrtBinHandle binHandle, const char *kernelName, aclrtFuncHandle *funcHandle)
{
  ACL_LOG_INFO("start to execute aclrtBinaryGetFunction");
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binHandle);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(kernelName);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(funcHandle);

  // currently not support multi kernel, so tilingKey always use 0
  (void)kernelName; // reserved param
  constexpr uint64_t tilingKey = 0UL;
  const rtError_t rtErr = rtBinaryGetFunction(binHandle, tilingKey, funcHandle);
  if (rtErr != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtBinaryGetFunction failed, runtime result = %d.", rtErr);
    return ACL_GET_ERRCODE_RTS(rtErr);
  }

  return ACL_SUCCESS;
}

aclError aclrtLaunchKernel(aclrtFuncHandle funcHandle, uint32_t blockDim, const void *argsData,
                           size_t argsSize, aclrtStream stream)
{
  ACL_PROFILING_REG(acl::AclProfType::AclrtLaunchKernel);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(funcHandle);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(argsData);

  rtLaunchArgsHandle argsHandlePtr;
  rtLaunchArgsHandle* argsHandle = &argsHandlePtr;
  const rtError_t rtErr1 = rtCreateLaunchArgs(argsSize, 0UL, 0UL, const_cast<void *>(argsData),
                                              argsHandle);
  if (rtErr1 != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtCreateLaunchArgs failed, runtime result = %d.", rtErr1);
    return ACL_GET_ERRCODE_RTS(rtErr1);
  }

  const rtError_t rtErr2 = rtLaunchKernelByFuncHandle(funcHandle, blockDim, argsHandlePtr, stream);
  if (rtErr2 != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtLaunchKernelByFuncHandle failed, runtime result = %d.", rtErr2);
    (void)rtDestroyLaunchArgs(argsHandlePtr);
    return ACL_GET_ERRCODE_RTS(rtErr2);
  }

  (void)rtDestroyLaunchArgs(argsHandlePtr);
  return ACL_SUCCESS;
}
